/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.meego.common.util;

import com.meego.common.log.GA;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.text.DecimalFormat;
import java.text.Normalizer;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.cliffc.high_scale_lib.NonBlockingHashtable;

/**
 *
 * @author TueHM
 */
public class StringUtils {

    private static NonBlockingHashtable _hashTableBadWord = null;
    private static String _patternBadWord = "";
    private static final String GEN_KEY = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    private static final String[] padding = {"", " ", "  ", "   ", "    ", "     ", "      ", "       ", "        ", "         ", "          "};

    /**
     * Returns space padding
     *
     * @param width amount of padding desired
     * @return string of spaces * width
     */
    public static String padding(int width) {
        if (width < 0) {
            throw new IllegalArgumentException("width must be > 0");
        }

        if (width < padding.length) {
            return padding[width];
        }

        char[] out = new char[width];
        for (int i = 0; i < width; i++) {
            out[i] = ' ';
        }
        return String.valueOf(out);
    }

    private static char getRandomChar() {
        Random rd = new Random();
        Integer number = Integer.valueOf(rd.nextInt(GEN_KEY.length()));
        return GEN_KEY.charAt(number.intValue());
    }

    /**
     * Generate the random string
     *
     * @param length The length of the string will be generated
     * @return The random string
     */
    public static String getRandomString(Integer length) {
        String result = "";

        for (int i = 0; i < length.intValue(); i++) {
            result = result + getRandomChar();
        }

        return result;
    }

    /**
     * Remove script tag from input string (include script tag content)
     *
     * @param data the string will be removed script tag
     * @return The string without script tag
     */
    public static String removeScriptTag(String data) {
        if ((data != null) && (data.length() > 0)) {
            return data.replaceAll("<\\s*script[^>]*>.*?</\\s*script[^>]*>", "");
        }
        return "";
    }

    /**
     * Check the string is included script tag or not
     *
     * @param data The string will be checked
     * @return true/false
     */
    public static boolean haveScriptTag(String data) {
        if (data == null) {
            return false;
        }

        return data.length() != removeScriptTag(data).length();
    }

    /**
     * Remove all tag from input string (keep tag content)
     *
     * @param data the string will be removed tag
     * @return The string after removed tag
     */
    public static String removeAllTag(String data) {
        if ((data != null) && (data.length() > 0)) {
            return data.replaceAll("<(.|\n)*?>", "");
        }
        return "";
    }

    /**
     * Check the string is included tag or not
     *
     * @param data The string will be checked
     * @return true/false
     */
    public static boolean haveTag(String data) {
        if (data == null) {
            return false;
        }

        return data.length() != removeAllTag(data).length();
    }

    /**
     * Remove the Unicode characters from string
     *
     * @param data The string will be removed unicode characters
     * @return true/false
     */
    public static String removeUnicode(String data) {
        if ((data != null) && (data.length() > 0)) {
            return data.replaceAll("[^\\p{ASCII}]", "");
        }
        return "";
    }

    /**
     * Transform the unicode string to non-unicode string
     *
     * @param data the string will be transform
     * @return The non-unicode string
     */
    public static String killUnicode(String data) {
        if ((data != null) && (data.length() > 0)) {
            data = data.replaceAll("Đ", "D");
            data = data.replaceAll("đ", "d");
            return Normalizer.normalize(data, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", "");
        }
        return "";
    }

    /**
     * Check the string contain the unicode characters or not
     *
     * @param data the string will be checked
     * @return true/false
     */
    public static boolean haveUnicode(String data) {
        if (data == null) {
            return false;
        }

        return data.length() != removeUnicode(data).length();
    }

    /**
     * Normalize a sequence of char values. The sequence will be normalized according to the specified normalization
     * from.
     *
     * @param data The sequence of char values to normalize.
     * @return The normalized String
     */
    public static String normalize(String data) {
        if ((data != null) && (data.length() > 0)) {
            return Normalizer.normalize(data, Normalizer.Form.NFKC);
        }
        return "";
    }

    /**
     * Remove bad word from the string
     *
     * @param data the string to remove
     * @return the removed string
     */
    public static String removeBadWord(String data) {
        if ((data != null) && (data.length() > 0) && (_patternBadWord.length() > 0) && (_hashTableBadWord != null) && (_hashTableBadWord.size() > 0)) {
            Matcher matcher = Pattern.compile(_patternBadWord).matcher(data);
            int i = 0;
            while (matcher.find()) {
                if (_hashTableBadWord.containsKey(matcher.group(i))) {
                    data = data.replaceAll(matcher.group(i), (String) _hashTableBadWord.get(matcher.group(i)));
                }
                i++;
            }

            return data;
        }
        return "";
    }

    public static boolean haveBadWord(String data) {
        if ((data != null) && (data.length() > 0)) {
            Matcher matcher = Pattern.compile(_patternBadWord).matcher(data);
            return matcher.find();
        }
        return false;
    }

    private static boolean loadBadWord(String filePath) {
        try {
            if (_hashTableBadWord == null) {
                ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
                InputStream inputData = classLoader.getResourceAsStream(filePath);
                if (inputData == null) {
                    return false;
                }
                _hashTableBadWord = new NonBlockingHashtable();
                String streamLine;
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputData, "UTF-8"));
                _patternBadWord = "(";
                while ((streamLine = bufferedReader.readLine()) != null) {
                    String[] strArr = streamLine.split(",");
                    if (strArr.length < 2) {
                        continue;
                    }
                    String key = strArr[0].trim().toLowerCase();

                    if (!_hashTableBadWord.containsKey(key)) {
                        _hashTableBadWord.put(key, strArr[1]);
                        _patternBadWord = _patternBadWord + key + "|";
                    }
                }
                _patternBadWord = _patternBadWord.replaceAll(".$", "");
                _patternBadWord += ")";
                bufferedReader.close();
            }
        } catch (Exception e) {
        }
        return false;
    }

    /**
     * Transform the unicode string to non-unicode string, remove the special character, replace whitespace by '-'
     * character
     *
     * @param data the string to slug
     * @return the slugged string
     */
    public static String slug(String data) {
        data = killUnicode(data).trim();
        if (data.length() > 0) {
            data = data.replaceAll("[^a-zA-Z0-9- ]*", "");
            data = data.replaceAll("[ ]{1,}", "-");
        }
        return data;
    }

    public static String removeSpecialCharacter(String data) {
        if (data.length() > 0) {
            data = data.replaceAll("[^a-zA-Z0-9- ]*", "");
        }
        return data;
    }

    /**
     * Transform the unicode string to non-unicode string, remove the special character, replace whitespace by '-'
     * character
     *
     * @param data the string to slug
     * @param length the length of return string
     * @return the slugged string
     */
    public static String slug(String data, int length) {
        String slugString = slug(data);
        return slug(data).substring(0, slugString.length() > length ? length : slugString.length());
    }

    public static String digitFormat(long value) {
        NumberFormat formatter = new DecimalFormat("#,##0");
        return formatter.format(value);
    }

    public static boolean isEmpty(String str) {
        return (str == null) || (str.length() == 0);
    }

    /**
     * Skip <i> stripChars </ i> at the leading of the string
     *
     * @param str the string to strip
     * @param stripChars the sequence of chars will be omitted
     * @return Returns a copy of the string, with leading <i>stripChars</i>omitted.
     */
    public static String stripStart(String str, String stripChars) {
        int strLen;
        if ((str == null) || ((strLen = str.length()) == 0)) {
            return str;
        }
        int start = 0;
        if (stripChars == null) {
            while ((start != strLen) && (Character.isWhitespace(str.charAt(start)))) {
                start++;
            }
        }
        if (stripChars.length() == 0) {
            return str;
        }
        while ((start != strLen) && (stripChars.indexOf(str.charAt(start)) != -1)) {
            start++;
        }
        return str.substring(start);
    }

    /**
     * Skip <i> stripChars </ i> at the trailing of the string
     *
     * @param str the string to strip
     * @param stripChars the sequence of chars will be omitted
     * @return Returns a copy of the string, with trailing <i>stripChars</i> omitted.
     */
    public static String stripEnd(String str, String stripChars) {
        int end;
        if ((str == null) || ((end = str.length()) == 0)) {
            return str;
        }
        if (stripChars == null) {
            while ((end != 0) && (Character.isWhitespace(str.charAt(end - 1)))) {
                end--;
            }
        }
        if (stripChars.length() == 0) {
            return str;
        }
        while ((end != 0) && (stripChars.indexOf(str.charAt(end - 1)) != -1)) {
            end--;
        }

        return str.substring(0, end);
    }

    /**
     * Skip <i> stripChars </i> at the leading and trailing of the string
     *
     * @param str the string to strip
     * @param stripChars the sequence of chars will be omitted
     * @return Returns a copy of the string, with leading and trailing <i>stripChars</i> omitted.
     */
    public static String strip(String str, String stripChars) {
        if (isEmpty(str)) {
            return str;
        }
        str = stripStart(str, stripChars);
        return stripEnd(str, stripChars);
    }

    /**
     * Convert the array of Objects to String
     *
     * @param array the array of Objects to join
     * @param separator the character to separate each item in array
     * @return the joined string
     */
    public static String join(Object[] array, String separator) {
        if (array == null) {
            return null;
        }
        return join(array, separator, 0, array.length);
    }

    /**
     *
     * Convert the array of Objects to String
     *
     * @param array the array of Objects to join
     * @param separator the character to separate each item in array
     * @param startIndex the begin index of item in the array wanna join
     * @param endIndex the end index of item in the array wanna join
     * @return the joined string
     */
    public static String join(Object[] array, String separator, int startIndex, int endIndex) {
        if (array == null) {
            return null;
        }
        if (separator == null) {
            separator = " ";
        }

        int bufSize = endIndex - startIndex;
        if (bufSize <= 0) {
            return "";
        }
        if (endIndex > array.length) {
            endIndex = array.length;
        }

        StringBuilder buf = new StringBuilder();

        for (int i = startIndex; i < endIndex; i++) {
            if (i > startIndex) {
                buf.append(separator);
            }
            if (array[i] != null) {
                if (array[i].toString().contains(separator) && !separator.equals("\"")) {
                    buf.append("\"");
                    buf.append(array[i]);
                    buf.append("\"");
                    continue;
                }
                buf.append(array[i]);
            }
        }
        return buf.toString();
    }

    /**
     * Convert the iterator to String
     *
     * @param iterator the iterator to join
     * @param separator the character to separate each item in iterator
     * @return the joined string
     */
    public static String join(Iterator iterator, String separator) {
        if (iterator == null) {
            return null;
        }
        if (!iterator.hasNext()) {
            return "";
        }
        Object first = iterator.next();
        if (!iterator.hasNext()) {
            return first == null ? "" : first.toString();
        }

        StringBuilder buf = new StringBuilder();
        if (first != null) {
            buf.append(first);
        }

        while (iterator.hasNext()) {
            if (separator != null) {
                buf.append(separator);
            }
            Object obj = iterator.next();
            if (obj != null) {
                if (obj.toString().contains(separator) && !separator.equals("\"")) {
                    buf.append("\"");
                    buf.append(obj);
                    buf.append("\"");
                    continue;
                }
                buf.append(obj);
            }
        }
        return buf.toString();
    }

    /**
     * convert the collection to string
     *
     * @param collection the collection to join
     * @param separator the character to separate each item in collection
     * @return the join string
     */
    public static String join(Collection collection, String separator) {
        if (collection == null) {
            return null;
        }
        return join(collection.iterator(), separator);
    }

    /**
     * Tests if a string is blank: null, emtpy, or only whitespace (" ", \r\n, \t, etc)
     *
     * @param string string to test
     * @return if string is blank
     */
    public static boolean isBlank(String string) {
        if (string == null || string.length() == 0) {
            return true;
        }

        int l = string.length();
        for (int i = 0; i < l; i++) {
            if (!StringUtils.isWhitespace(string.codePointAt(i))) {
                return false;
            }
        }
        return true;
    }

    /**
     * Tests if a string is numeric, i.e. contains only digit characters
     *
     * @param string string to test
     * @return true if only digit chars, false if empty or null or contains non-digit chrs
     */
    public static boolean isNumeric(String string) {
        if (string == null || string.length() == 0) {
            return false;
        }

        int l = string.length();
        for (int i = 0; i < l; i++) {
            if (!Character.isDigit(string.codePointAt(i))) {
                return false;
            }
        }
        return true;
    }

    /**
     * Tests if a code point is "whitespace" as defined in the HTML spec.
     *
     * @param c code point to test
     * @return true if code point is whitespace, false otherwise
     */
    public static boolean isWhitespace(int c) {
        return c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r';
    }

    /**
     * Splits this string around matches of the given regular expression
     *
     * @param val The input string
     * @param regex : The regular expression is used to split the string
     * @return The list of strings computed by splitting this string around matches of the given regular expression
     */
    public static List<String> toList(String str, String regex) {
        ArrayList<String> list = new ArrayList<String>();

        if (str != null) {
            boolean quoted = false;
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < str.length(); i++) {
                if (str.charAt(i) == '"') {
                    quoted = !quoted;
                    sb.append(str.charAt(i));
                } else if ((!quoted) && (regex.indexOf(str.charAt(i)) >= 0)) {
                    list.add(sb.toString().trim().replaceAll("\"", ""));
                    sb.setLength(0);
                } else {
                    sb.append(str.charAt(i));
                }
            }
            if (sb.length() > 0) {
                list.add(sb.toString().trim().replaceAll("\"", ""));
            }
        }
        return list;
    }

    /**
     * Splits this string around matches of the given regular expression
     *
     * @param <T> The subclass of Number (support: Long, Integer, Float, Double)
     * @param str The String to be used to create the list of the specified type
     * @param regex The regular expression is used to split the string
     * @param clazz Must be a subclass of Number. Defines the type of the new List. Only support: Long, Integer, Float,
     * Double
     * @return The list of specified type is computed by splitting this string around matches of the given regular
     * expression <br><b>Note: </b> items which are not valid number format will be skip(not add to return data list)
     */
    public static <T extends Number> List<T> toList(String str, String regex, final Class<T> clazz) {
        List<T> list = new ArrayList<T>();
        if (str != null) {
            boolean quoted = false;
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < str.length(); i++) {
                if (str.charAt(i) == '"') {
                    quoted = !quoted;
                    sb.append(str.charAt(i));
                } else if ((!quoted) && (regex.indexOf(str.charAt(i)) >= 0)) {
                    try {
                        if (clazz.equals(Integer.class)) {
                            list.add((T) Integer.valueOf(sb.toString().trim().replaceAll("\"", "")));
                        } else if (clazz.equals(Long.class)) {
                            list.add((T) Long.valueOf(sb.toString().trim().replaceAll("\"", "")));
                        } else if (clazz.equals(Float.class)) {
                            list.add((T) Float.valueOf(sb.toString().trim().replaceAll("\"", "")));
                        } else if (clazz.equals(Double.class)) {
                            list.add((T) Double.valueOf(sb.toString().trim().replaceAll("\"", "")));
                        } else {
//                        String.format("Type %s is not supported (yet)", clazz.getName());
                        }
                    } catch (NumberFormatException e) {
                    }
                    sb.setLength(0);
                } else {
                    sb.append(str.charAt(i));
                }
            }
            if (sb.length() > 0) {
                try {
                    if (clazz.equals(Integer.class)) {
                        list.add((T) Integer.valueOf(sb.toString().trim().replaceAll("\"", "")));
                    } else if (clazz.equals(Long.class)) {
                        list.add((T) Long.valueOf(sb.toString().trim().replaceAll("\"", "")));
                    } else if (clazz.equals(Float.class)) {
                        list.add((T) Float.valueOf(sb.toString().trim().replaceAll("\"", "")));
                    } else if (clazz.equals(Double.class)) {
                        list.add((T) Double.valueOf(sb.toString().trim().replaceAll("\"", "")));
                    } else {
//                    String.format("Type %s is not supported (yet)", clazz.getName());
                    }
                } catch (NumberFormatException e) {
                }
            }
        }
        return list;
    }

    public static String decodeString(byte[] data) {
        String rv = null;
        try {
            if (data != null) {
                rv = new String(data, "UTF-8");
            }
        } catch (UnsupportedEncodingException e) {
            GA.service.error(e);
        }
        return rv;
    }

    public static byte[] encodeString(String in) {
        byte[] rv = null;
        try {
            rv = in.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            GA.service.error(e);
        }
        return rv;
    }

    /**
     * Replace patterns in the input string which match with replaces
     *
     * @param input The target string will be modified
     * @param replacement the replacement pattern
     * @param replaceds the pattern will be replaced
     * @return
     */
    public static String replace(String input, String replacement, String... replaces) {
        for (String regex : replaces) {
            if (input.contains(regex)) {
                input = input.replace(regex, replacement);
            }
        }
        input = input.replaceAll(replacement + "{2,}", replacement);
        input = strip(input, replacement);
        return input;
    }

    /**
     *
     * @param text
     * @param regex
     * @return Ex: + "abaca", "a.a" -> [aba, aca] + "abaa", "a.*a" -> [abaa, aa]
     */
    public static List<String> getAllMatches(String text, String regex) {
        List<String> matches = new ArrayList<String>();
        Matcher m = Pattern.compile("(?=(" + regex + "))").matcher(text);
        while (m.find()) {
            matches.add(m.group(1));
        }
        return matches;
    }

    public static String hidePassword(String data) {
        if (data == null) {
            return "";
        }
        return String.format("%" + data.length() + "s", "").replace(' ', '*');
    }

    public static String normaliseWhitespace(String string) {
        StringBuilder sb = new StringBuilder(string.length());

        boolean lastWasWhite = false;
        boolean modified = false;

        int l = string.length();
        for (int i = 0; i < l; i++) {
            int c = string.codePointAt(i);
            if (isWhitespace(c)) {
                if (lastWasWhite) {
                    modified = true;
                    continue;
                }
                if (c != ' ') {
                    modified = true;
                }
                sb.append(' ');
                lastWasWhite = true;
            } else {
                sb.appendCodePoint(c);
                lastWasWhite = false;
            }
        }
        return modified ? sb.toString() : string;
    }

    public static boolean in(String needle, String... haystack) {
        for (String hay : haystack) {
            if (hay.equals(needle)) {
                return true;
            }
        }
        return false;
    }
    
    public static String nullToEmpry(String data){
        if(data == null){
            return new String();
        }
        return data.trim();
    }
    
    public static String iso8859ToUtf8(String data){
        if(data == null){
            return new String();
        }
        try {
            return new String(data.getBytes ("iso-8859-1"), "UTF-8");
        } catch (UnsupportedEncodingException ex) {
            return new String();
        }
    }
    
    public static String removeNonPrintableCharactor(String data){
        return data.replaceAll("\\p{C}", "");
    }

//    static{
//        loadBadWord();
//    }
    public static void main(String[] args) {
        System.out.println(slug("ước ao một mình tôi ông cao thắng", 100));
    }
}
